<template>
    <button class="a-button" :disabled="props.disabled" :class="[
        `color-${props.color}`,
        `size-${props.size}`,
        { disabled: props.disabled },
        { sharp: props.sharp },
        { 'c-circle': props.circle },
        { round: props.round },
        props.square || props.circle ? `c-square-${props.size}` : '',
        { 'c-w-100': props.block },
        { loading: state.myLoading },
        { plain: props.plain },
        { link: props.link },
        { hollow: props.hollow },
        props.align ? `c-align-${props.align}` : '',
        { active: props.active },
        { 'half-height': props.halfHeight },
    ]">
        <span class="fa fa-fw fa-spinner fa-spin" v-if="state.myLoading"></span>
        <slot v-if="!((props.square || props.circle) && state.myLoading)"></slot>
    </button>
</template>

<style lang="scss" scoped>
@use "sass:math";
@import "../scss/vars";

.a-button {
    user-select: none;

    &:not(.hollow) {
        border: none;
    }

    &.hollow {
        border-width: 1px;
        border-style: solid;
        box-sizing: border-box;
    }

    &:not(.loading):not(.disabled) {
        cursor: pointer;
    }

    &.disabled {
        opacity: 0.5;
        cursor: not-allowed;
    }

    &.loading {
        opacity: 0.5;
        pointer-events: none;
    }

    @each $colorPackageName,
    $colorPackageValue in $colorPackages {
        $frontColor: map-get($colorPackageValue, "frontColor");
        $bgColor: map-get($colorPackageValue, "bgColor");
        $frontColorReverse: map-get($colorPackageValue, "frontColorReverse");
        $bgColorReverse: map-get($colorPackageValue, "bgColorReverse");

        &.color-#{$colorPackageName} {
            outline-color: darken($bgColor, 10%);

            &:not(.link):not(.plain):not(.hollow) {
                color: $frontColor;
                background-color: $bgColor;

                &:not(.disabled) {
                    &:hover {
                        background-color: lighten($bgColor, 10%);
                    }

                    &:active,
                    &.active {
                        background-color: darken($bgColor, 10%);
                    }
                }
            }

            &.plain {
                color: $frontColorReverse;
                background-color: transparent;

                &:not(.disabled) {
                    &:hover {
                        color: $frontColor;
                        background-color: lighten($bgColor, 10%);
                    }

                    &:active,
                    &.active {
                        color: $frontColor;
                        background-color: darken($bgColor, 10%);
                    }
                }
            }

            &.link {
                color: $frontColorReverse;
                background-color: transparent;

                &:not(.disabled) {
                    &:hover {
                        color: lighten($frontColorReverse, 10%);
                    }

                    &:active,
                    &.active {
                        color: darken($frontColorReverse, 10%);
                    }
                }
            }

            &.hollow {
                border-color: $frontColorReverse;
                color: $frontColorReverse;
                background-color: transparent;

                &:not(.disabled) {
                    &:hover {
                        color: lighten($frontColorReverse, 10%);
                    }

                    &:active,
                    &.active {
                        color: darken($frontColorReverse, 10%);
                    }
                }
            }
        }
    }

    @each $sizePackageName,
    $sizePackageValue in $sizePackages {
        &.size-#{$sizePackageName} {
            &:not(.c-square-#{$sizePackageName}) {
                padding-left: map-get($sizePackageValue, "space");
                padding-right: map-get($sizePackageValue, "space");
                height: map-get($sizePackageValue, "size");
            }

            font-size: map-get($sizePackageValue, "fontSize");

            &:not(.sharp):not(.round):not(.c-circle) {
                border-radius: map-get($sizePackageValue, "borderRadius");
            }

            &.round:not(.sharp):not(.c-circle) {
                border-radius: map-get($sizePackageValue, "size") * 0.5;
            }

            &.half-height {
                height: math.div(map-get($sizePackageValue, "size"),
                        2) !important;
                line-height: 0;
            }
        }
    }
}
</style>

<script setup lang="ts">
import { AlignType, ColorType, SizeType } from '@/types'
import { reactive, watch } from 'vue'

interface PropsType {
    color?: ColorType
    disabled?: boolean
    size?: SizeType
    sharp?: boolean
    circle?: boolean
    round?: boolean
    square?: boolean
    block?: boolean
    loading?: boolean | Promise<void>
    plain?: boolean
    link?: boolean
    hollow?: boolean
    align?: AlignType
    active?: boolean
    halfHeight?: boolean
}
const props = withDefaults(defineProps<PropsType>(), {
    color: 'default',
    disabled: false,
    size: 'm',
    sharp: false,
    circle: false,
    round: false,
    square: false,
    block: false,
    loading: false,
    plain: false,
    link: false,
    hollow: false,
    align: undefined,
    active: false,
    halfHeight: false
})

interface StateType {
    myLoading: boolean
}
const state = reactive<StateType>({
    myLoading: false
})
watch(() => props.loading, () => {
    updateLoading()
})
const updateLoading = () => {
    if (props.loading instanceof Promise) {
        state.myLoading = true
        props.loading.finally(() => {
            state.myLoading = false
        })
    } else {
        state.myLoading = props.loading
    }
}
</script>